package org.jim.server.command.handler;

import org.apache.commons.collections4.CollectionUtils;
import org.jim.core.*;
import org.jim.core.config.ImConfig;
import org.jim.core.exception.ImException;
import org.jim.core.message.MessageHelper;
import org.jim.core.packets.*;
import org.jim.core.protocol.IProtocol;
import org.jim.core.utils.JsonKit;
import org.jim.server.ImServerChannelContext;
import org.jim.server.JimServerAPI;
import org.jim.server.command.AbstractCmdHandler;
import org.jim.server.command.CommandManager;
import org.jim.server.processor.login.LoginCmdProcessor;
import org.jim.server.config.ImServerConfig;
import org.jim.server.protocol.ProtocolManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Objects;

/**
 * 登录消息命令处理器
 * @author WChao
 * @date 2018年4月10日 下午2:40:07
 */
public class LoginReqHandler extends AbstractCmdHandler {

	private static Logger log = LoggerFactory.getLogger(LoginReqHandler.class);

	/**
	 * 重写handler方法以处理登录消息命令
	 *
	 * @param packet 包含登录请求数据的ImPacket对象
	 * @param imChannelContext 通道上下文信息，用于处理连接相关信息
	 * @return 处理登录请求后返回的ImPacket对象
	 * @throws ImException 如果处理过程中发生错误
	 */
	@Override
	public ImPacket handler(ImPacket packet, ImChannelContext imChannelContext) throws ImException {
	    // 记录登录消息命令操作的日志信息
	    log.info("【登录消息命令处理器】操作");

	    ImServerChannelContext imServerChannelContext = (ImServerChannelContext)imChannelContext;
	    /**
	     * 将字节数据 反序列化为 LoginReqBody对象
	     */
	    LoginReqBody loginReqBody = JsonKit.toBean(packet.getBody(), LoginReqBody.class);

	    log.info("处理登录数据 loginReqBody：{}",loginReqBody);

	    // 获取登录命令处理器实例
	    LoginCmdProcessor loginProcessor = this.getSingleProcessor(LoginCmdProcessor.class);

	    // 创建一个成功的登录响应体
	    LoginRespBody loginRespBody = LoginRespBody.success();

	    // 通过处理器获取用户信息
	    User user = getUserByProcessor(imChannelContext, loginProcessor, loginReqBody, loginRespBody,imServerChannelContext);

//	    // 获取当前连接使用的协议类型
//	    IProtocol protocol = imServerChannelContext.getProtocolHandler().getProtocol();
//
//	    // 设置用户的终端协议信息
//	    user.setTerminal(Objects.isNull(protocol) ? Protocol.UNKNOWN : protocol.name());
//
//	    // 绑定用户到当前服务器通道上下文
//	    JimServerAPI.bindUser(imServerChannelContext, user);
//
//	    // 初始化绑定或者解绑群组;
//	    initGroup(imChannelContext, user);
//
//	    // 登录成功后的处理操作
//	    loginProcessor.onSuccess(user, imChannelContext);

	    // 返回登录响应包
	    return ProtocolManager.Converter.respPacket(loginRespBody, imChannelContext);
	}

	/**
	 * 根据用户配置的自定义登录处理器获取业务组装的User信息
	 * @param imChannelContext 通道上下文
	 * @param loginProcessor 登录自定义业务处理器
	 * @param loginReqBody 登录请求体
	 * @param loginRespBody 登录响应体
	 * @return 用户组装的User信息
	 * @throws ImException
	 */
	private User getUserByProcessor(ImChannelContext imChannelContext, LoginCmdProcessor loginProcessor, LoginReqBody loginReqBody,
									LoginRespBody loginRespBody,ImServerChannelContext imServerChannelContext)throws ImException{
	    // 如果登录处理器为空，则直接根据请求体中的用户ID构建一个在线状态的User对象并返回
	    if(Objects.isNull(loginProcessor)){
//			log.info("登录处理器为空，则直接根据请求体中的用户ID构建一个在线状态的User对象并返回");
//	        User user = User.newBuilder().userId(loginReqBody.getUserId()).status(UserStatusType.ONLINE.getStatus()).build();
			log.error("userId:{}, password:{}，登录失败，登录处理器为空！！！", loginReqBody.getUserId(), loginReqBody.getPassword());
	        return null;
	    }
	    // 调用自定义登录处理器的登录方法处理登录请求，并获取响应体
	    loginRespBody = loginProcessor.doLogin(loginReqBody, imChannelContext);
	    // 如果登录响应体为空或登录失败，则记录错误日志，并执行登录失败后的处理逻辑
	    if (Objects.isNull(loginRespBody) || loginRespBody.getCode() != ImStatus.C10007.getCode()) {
	        log.error("登录失败！！！ userId:{}, password:{}", loginReqBody.getUserId(), loginReqBody.getPassword());
	        loginProcessor.onFailed(imChannelContext);
	        // 发送登录失败的响应包，并移除无效的连接
	        JimServerAPI.bSend(imChannelContext, ProtocolManager.Converter.respPacket(loginRespBody, imChannelContext));
	        JimServerAPI.remove(imChannelContext, "userId or token is incorrect");
	        return null;
	    }

		/**
		 * 登录成功
		 */
		User user = loginRespBody.getUser();

		// 获取当前连接使用的协议类型
	    IProtocol protocol = imServerChannelContext.getProtocolHandler().getProtocol();

	    // 设置用户的终端协议信息
	    user.setTerminal(Objects.isNull(protocol) ? Protocol.UNKNOWN : protocol.name());

	    // 绑定用户到当前服务器通道上下文
	    Boolean isSuccess = JimServerAPI.bindUser(imServerChannelContext, user);

		if(!isSuccess){
			loginProcessor.onFailed(imChannelContext);
			JimServerAPI.bSend(imChannelContext, ProtocolManager.Converter.respPacket(loginRespBody, imChannelContext));
			JimServerAPI.remove(imChannelContext, "userId or token is incorrect");
		   log.info("绑定用户到当前服务器通道上下文失败！");
		   return null;
		}

	    // 初始化绑定或者解绑群组;
	    initGroup(imChannelContext, user);

	    // 登录成功后的处理操作
	    loginProcessor.onSuccess(user, imChannelContext);

		return user;
	}

	/**
	 * 初始化绑定或者解绑群组;
	 */
	public void initGroup(ImChannelContext imChannelContext , User user)throws ImException{
		String userId = user.getUserId();
		List<Group> groups = user.getGroups();
		if(CollectionUtils.isEmpty(groups))return;

		ImServerConfig imServerConfig = ImConfig.Global.get();
		boolean isStore = ImServerConfig.ON.equals(imServerConfig.getIsStore());
		MessageHelper messageHelper = imServerConfig.getMessageHelper();
		List<String> groupIds = null;
		if(isStore){
			groupIds = messageHelper.getGroups(userId);
		}
		//绑定群组
		for(Group group : groups){
			if(isStore && CollectionUtils.isNotEmpty(groupIds)){
				groupIds.remove(group.getGroupId());
			}
			ImPacket groupPacket = new ImPacket(Command.COMMAND_JOIN_GROUP_REQ,JsonKit.toJsonBytes(group));
			try {
				JoinGroupReqHandler joinGroupReqHandler = CommandManager.getCommand(Command.COMMAND_JOIN_GROUP_REQ, JoinGroupReqHandler.class);
				joinGroupReqHandler.handler(groupPacket, imChannelContext);
			} catch (Exception e) {
				log.error(e.toString(),e);
			}
		}
		if(isStore && groupIds != null){
			for(String groupId : groupIds){
				messageHelper.getBindListener().onAfterGroupUnbind(imChannelContext, Group.newBuilder().groupId(groupId).build());
			}
		}
	}
	@Override
	public Command command() {
		return Command.COMMAND_LOGIN_REQ;
	}

}
